package com.ccteam.admin.viewmodels.album

import android.app.Application
import androidx.lifecycle.*
import com.ccteam.admin.R
import com.ccteam.admin.core.ADD_TYPE
import com.ccteam.admin.core.EDIT_TYPE
import com.ccteam.admin.repositories.AlbumAdminRepository
import com.ccteam.admin.repositories.UploadAdminRepository
import com.ccteam.admin.utils.*
import com.ccteam.admin.vo.Resource
import com.ccteam.model.album.AlbumDTO
import com.ccteam.model.album.AlbumInfoNoIdDTO
import com.ccteam.model.album.AlbumVO
import com.ccteam.network.ApiError
import com.ccteam.network.exception.ApiException
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

/**
 * @author Xiaoc
 * @since 2021/3/2
 */
@HiltViewModel
class AlbumEditViewModel @Inject constructor(
    application: Application,
    private val albumRepository: AlbumAdminRepository,
    private val uploadRepository: UploadAdminRepository,
    private val uploadFileUtils: UploadFileUtils,
    savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {

    /**
     * 专辑名是否成功
     */
    private val albumNameSuccess = MutableLiveData(false)

    /**
     * 专辑简介是否成功
     */
//    private val albumIntroductionSuccess = MutableLiveData(false)

    /**
     * 专辑年份是否成功
     */
    private val albumYearSuccess = MutableLiveData(false)

    /**
     * 专辑封面是否成功
     */
    private val albumUrlSuccess = MutableLiveData(false)

    /**
     * 专辑歌手选择是否成功
     */
    private val albumArtistSuccess = MutableLiveData(false)

    private val albumIdLiveData = MutableLiveData<String>()


    /**
     * 编辑时的加载信息
     */
    private val _editLoadMessage = MediatorLiveData<Event<LoadMessage>>()
    val editLoadMessage: LiveData<Event<LoadMessage>> get() = _editLoadMessage

    /**
     * 删除时的加载信息
     */
    private val _deleteLoadMessage = MediatorLiveData<Event<LoadMessage>>()
    val deleteLoadMessage: LiveData<Event<LoadMessage>> get() = _deleteLoadMessage

    /**
     * 最原始的专辑信息（例如编辑时最初的专辑信息，方便与修改后的作比较）
     */
    private var originAlbumInfo: AlbumEditInfo? = null

    /**
     * 当前类型为 编辑专辑 or 新增专辑
     * 仅可赋值一次
     */
    private val type: Int = savedStateHandle["albumEditType"] ?: ADD_TYPE

    private val _editAlbumInfo = MediatorLiveData<AlbumEditInfo>()
    val editAlbumInfo get() = _editAlbumInfo

    private val _loadingMessage = MutableLiveData<LoadMessage>(LoadMessage.NotLoading)
    val loadMessage: LiveData<LoadMessage> get() = _loadingMessage

    /**
     * 是否启用编辑按钮（当满足条件时启用）
     */
    private val _editButtonEnable = MediatorLiveData<Boolean>()
    val editButtonEnable: LiveData<Boolean> get() = _editButtonEnable

    /**
     * 是否启用删除按钮（当满足条件时启用）
     */
    private val _deleteButtonEnable = MediatorLiveData<Boolean>()
    val deleteButtonEnable: LiveData<Boolean> get() = _deleteButtonEnable

    init {
        _editButtonEnable.addSource(albumNameSuccess){
            _editButtonEnable.value = it
                    && albumYearSuccess.value == true
                    && albumUrlSuccess.value == true
                    && albumArtistSuccess.value == true
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(albumYearSuccess){
            _editButtonEnable.value = it && albumNameSuccess.value == true
                    && albumUrlSuccess.value == true
                    && albumArtistSuccess.value == true
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(albumUrlSuccess){
            _editButtonEnable.value = it && albumNameSuccess.value == true
                    && albumYearSuccess.value == true
                    && albumArtistSuccess.value == true
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(albumArtistSuccess){
            _editButtonEnable.value = it
                    && albumYearSuccess.value == true
                    && albumUrlSuccess.value == true
                    && albumNameSuccess.value == true
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(_editLoadMessage){
            val enable = it?.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && albumArtistSuccess.value == true
                    && albumYearSuccess.value == true
                    && albumUrlSuccess.value == true
                    && albumNameSuccess.value == true
            _editButtonEnable.value = enable
            _deleteButtonEnable.value = it.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(_deleteLoadMessage){
            val enable = it?.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && albumArtistSuccess.value == true
                    && albumYearSuccess.value == true
                    && albumUrlSuccess.value == true
                    && albumNameSuccess.value == true
            _editButtonEnable.value = enable
            _deleteButtonEnable.value = it.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editAlbumInfo.addSource(albumIdLiveData){
            refreshAlbumInfo()
        }

        albumIdLiveData.setValueIfNew(savedStateHandle.get<String>("albumId"))

        if(type == ADD_TYPE){
            _editAlbumInfo.value = AlbumEditInfo()
        }
    }

    /**
     * 设置专辑名是否成功
     */
    fun setAlbumNameSuccess(isSuccess: Boolean) {
        albumNameSuccess.value = isSuccess
    }

    /**
     * 设置专辑名
     */
    fun setAlbumName(albumName: String) {
        _editAlbumInfo.value?.albumName = albumName
    }

    /**
     * 设置专辑简介
     */
    fun setAlbumIntroduction(albumIntroduction: String) {
        _editAlbumInfo.value?.introduction = albumIntroduction
    }

//    /**
//     * 设置专辑简介是否成功
//     */
//    fun setAlbumIntroductionSuccess(isSuccess: Boolean) {
//        albumIntroductionSuccess.value = isSuccess
//    }

    /**
     * 设置专辑年份
     */
    fun setAlbumYear(albumYear: String) {
        _editAlbumInfo.value?.albumYear = albumYear
    }

    /**
     * 设置专辑年份是否成功
     */
    fun setAlbumYearSuccess(isSuccess: Boolean) {
        albumYearSuccess.value = isSuccess
    }

    /**
     * 设置专辑封面地址
     */
    fun setAlbumUrl(albumUrl: String) {
        _editAlbumInfo.value?.imgUrl = albumUrl
    }

    /**
     * 设置专辑封面地址是否成功
     */
    fun setAlbumUrlSuccess(isSuccess: Boolean) {
        albumUrlSuccess.value = isSuccess
    }

    /**
     * 设置专辑歌手
     */
    fun setAlbumArtist(artistId: String,albumArtist: String) {
        _editAlbumInfo.value?.artistName = albumArtist
        _editAlbumInfo.value?.artistId = artistId
    }

    /**
     * 设置专辑封面地址是否成功
     */
    fun setAlbumArtistSuccess(isSuccess: Boolean) {
        albumArtistSuccess.value = isSuccess
    }

    /**
     * 更新编辑后的专辑信息，因为在外部设置不同的更新属性时会导致一些问题
     * 所以手动提供此方法进行调用
     */
    fun updateAlbumEditInfo(){
        _editAlbumInfo.value = _editAlbumInfo.value
    }

    fun refreshAlbumInfo(){
        _loadingMessage.value = LoadMessage.Loading

        albumIdLiveData.value?.let { albumId ->
            viewModelScope.launch {
                val result = albumRepository.getAlbumInfo(albumId)

                if(result is Resource.Success){
                    _loadingMessage.value = LoadMessage.NotLoading

                    originAlbumInfo = AlbumEditInfo.toAlbumEditInfo(result.data)
                    _editAlbumInfo.value = AlbumEditInfo.toAlbumEditInfo(result.data)

                    setAlbumArtistSuccess(!originAlbumInfo?.artistId.isNullOrEmpty())

                } else {
                    _loadingMessage.value = LoadMessage.Error(ErrorMessage(ApiError.unknownCode,result.message))
                }

            }
        }
    }

    fun deleteAlbumInfo(){
        // 将其设置为 请求中 状态
        _deleteLoadMessage.value = Event(LoadMessage.Loading)

        viewModelScope.launch {
            albumIdLiveData.value?.let { albumId ->
                val result = albumRepository.deleteAlbumInfo(albumId)
                handleDeleteResult(result)
            }
        }
    }

    /**
     * 编辑和发布时调用此方法
     * 会先进行正确性检验，如果失败，会发出 [errorMessage] 提示相关信息
     * 如果正确，则直接进行对应内容的提交
     */
    fun editOrAddAlbumInfo() {
        val application = getApplication<Application>()
        if(_editButtonEnable.value != true || _editAlbumInfo.value == null){
            _editLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.unknownCode,application.getString(R.string.description_other_error))))
            return
        }

        if(_editAlbumInfo.value == originAlbumInfo){
            _editLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.unknownCode,application.getString(R.string.description_error_equal))))
            return
        }

        // 将其设置为 请求中 状态
        _editLoadMessage.value = Event(LoadMessage.Loading)

        /**
         * 上传前会检测头像是否为本地的头像，如果为本地头像
         * 则先上传获得文件地址后再更新内容
         */
        viewModelScope.launch(
            CoroutineExceptionHandler { c, throwable ->
                val errorMessage = if (throwable is ApiException) {
                    ErrorMessage(throwable.errorCode, throwable.message)
                } else {
                    ErrorMessage(ApiError.unknownCode, throwable.message)
                }
                _editLoadMessage.value = Event(LoadMessage.Error(errorMessage))
            }
        ) {
            uploadAlbumPhoto(_editAlbumInfo.value?.imgUrl)
            handleRequestEditAddAlbumInfo()
        }
    }

    /**
     * 上传专辑头像
     */
    private suspend fun uploadAlbumPhoto(photoUri: String?) {
        val application = getApplication<Application>()

        /**
         * 如果是本地头像地址，则进行文件上传
         */
        if (photoUri?.startsWith("content://") == false) {
            setAlbumUrl(photoUri)
            return
        }

        val result = uploadRepository.getImageToken()
        // 检测token是否获取成功
        if (result !is Resource.Success || result.data.isNullOrEmpty()) {
            throw ApiException(ApiError.serverErrorCode, "获取Token失败")
        }
        val token = result.data

        suspendCoroutine<String> { cn ->
            viewModelScope.launch{
                uploadFileUtils.upload(application, token, photoUri, { }, { fileUrl ->
                    setAlbumUrl(fileUrl)
                    cn.resume(fileUrl)
                }, { errorMessage ->
                    cn.resumeWithException(ApiException(ApiError.serverErrorCode, errorMessage))
                })
            }
        }

    }

    private fun handleRequestEditAddAlbumInfo(){

        // 根据不同的类型进行不同的API调用请求
        if (type == EDIT_TYPE) {
            val editInfo = _editAlbumInfo.value?.toEditAlbumInfoDto()
            editInfo?.let {
                viewModelScope.launch {
                    val result = albumRepository.editAlbumInfo(editInfo)
                    handleEditResult(result)
                }
            }
        } else {
            val addInfo = _editAlbumInfo.value?.toAddAlbumInfoDto()
            addInfo?.let {
                viewModelScope.launch {
                    val result = albumRepository.addAlbumInfo(addInfo)
                    handleEditResult(result)
                }
            }
        }
    }

    private fun handleEditResult(result: Resource<Nothing?>){
        if(result is Resource.Success){
            _editLoadMessage.value = Event(LoadMessage.Success)
        } else {
            _editLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode,result.message)))
        }
    }

    private fun handleDeleteResult(result: Resource<Nothing?>){
        if(result is Resource.Success){
            _deleteLoadMessage.value = Event(LoadMessage.Success)
        } else {
            _deleteLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode,result.message)))
        }
    }

    /**
     * Album专辑编辑的数据类
     * 使用该类是因为该类字段允许全为空，且具备基本的判断功能
     */
    data class AlbumEditInfo(
        var id: String? = null,
        var albumName: String? = null,
        var introduction: String? = null,
        var albumYear: String? = null,
        var imgUrl: String? = null,
        var artistId: String? = null,
        var artistName: String? = null
    ){
        companion object{

            fun toAlbumEditInfo(albumVO: AlbumVO?): AlbumEditInfo{
                return AlbumEditInfo(albumVO?.id,albumVO?.name,albumVO?.introduction,albumVO?.albumYear,albumVO?.imgUrl
                    ,albumVO?.artistId,albumVO?.artistName)
            }
        }

        fun toEditAlbumInfoDto(): AlbumDTO{
            return AlbumDTO(
                id!!,
                albumYear!!,
                artistId!!,
                artistName!!,
                imgUrl!!,
                introduction,
                albumName!!
            )
        }

        fun toAddAlbumInfoDto(): AlbumInfoNoIdDTO{
            return AlbumInfoNoIdDTO(
                albumYear!!,
                artistId!!,
                artistName!!,
                imgUrl!!,
                introduction,
                albumName!!
            )
        }


    }
}